"""
订阅管理服务类
负责订阅的CRUD操作和Stripe订阅同步
"""

import stripe
import uuid
import logging
from datetime import datetime
from typing import Optional, Dict, Any, List
from fastapi import HTTPException

from utils.config import Config
from utils.data_store import DataStore
from models.subscription_models import (
    SubscriptionCreateRequest, 
    SubscriptionCheckoutRequest,
    SubscriptionUpdateRequest,
    SubscriptionUpgradeRequest
)

logger = logging.getLogger(__name__)


class SubscriptionService:
    """订阅管理服务类"""
    
    def __init__(self, customer_service=None, product_service=None):
        self.subscriptions = DataStore.load_data(Config.SUBSCRIPTIONS_FILE)
        self.customer_service = customer_service
        self.product_service = product_service
    
    def create_subscription(self, request: SubscriptionCreateRequest) -> Dict[str, Any]:
        """创建订阅"""
        # 重新加载最新数据
        customers_data = DataStore.load_data(Config.CUSTOMERS_FILE)
        products_data = DataStore.load_data(Config.PRODUCTS_FILE)
        
        # 验证客户是否存在
        customer = customers_data.get(request.customer_id)
        if not customer:
            raise HTTPException(status_code=404, detail="客户不存在")
        
        # 验证产品是否存在
        product = products_data.get(request.product_id)
        if not product:
            raise HTTPException(status_code=404, detail="产品不存在")
        
        # 检查是否已有订阅（任何状态）
        for sub_id, sub_data in self.subscriptions.items():
            if (sub_data['customer_id'] == request.customer_id and 
                sub_data['product_id'] == request.product_id):
                if sub_data['status'] == 'active':
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已订阅该产品"
                    )
                elif sub_data['status'] in ['incomplete']:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的未付款订阅，请先处理现有订阅"
                    )
                else:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的订阅记录"
                    )
        
        try:
            # 创建Stripe订阅
            stripe_subscription = stripe.Subscription.create(
                customer=customer['stripe_customer_id'],
                items=[{"price": product['stripe_price_id']}],
                payment_behavior=request.payment_behavior,
                expand=["latest_invoice.payment_intent"],
                metadata=request.metadata or {}
            )
            
            # 生成本地订阅ID
            local_subscription_id = str(uuid.uuid4())
            
            # 构建订阅数据
            subscription_data = {
                'id': local_subscription_id,
                'stripe_subscription_id': stripe_subscription.id,
                'customer_id': request.customer_id,
                'product_id': request.product_id,
                'status': stripe_subscription.status,
                'current_period_start': stripe_subscription.current_period_start,
                'current_period_end': stripe_subscription.current_period_end,
                'cancel_at_period_end': stripe_subscription.cancel_at_period_end,
                'metadata': request.metadata or {},
                'created_at': datetime.now().isoformat(),
                'updated_at': datetime.now().isoformat()
            }
            
            # 保存到本地存储
            self.subscriptions[local_subscription_id] = subscription_data
            DataStore.save_data(Config.SUBSCRIPTIONS_FILE, self.subscriptions)
            
            logger.info(f"订阅创建成功: {local_subscription_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"创建订阅失败: {str(e)}")
            raise HTTPException(status_code=500, detail="创建订阅失败")

    def create_subscription_checkout(self, request: SubscriptionCheckoutRequest) -> Dict[str, Any]:
        """创建订阅支付会话"""
        # 重新加载最新数据
        customers_data = DataStore.load_data(Config.CUSTOMERS_FILE)
        products_data = DataStore.load_data(Config.PRODUCTS_FILE)
        
        # 验证客户是否存在
        customer = customers_data.get(request.customer_id)
        if not customer:
            raise HTTPException(status_code=404, detail="客户不存在")
        
        # 验证产品是否存在
        product = products_data.get(request.product_id)
        if not product:
            raise HTTPException(status_code=404, detail="产品不存在")
        
        # 检查是否已有订阅（任何状态）
        for sub_id, sub_data in self.subscriptions.items():
            if (sub_data['customer_id'] == request.customer_id and 
                sub_data['product_id'] == request.product_id):
                if sub_data['status'] == 'active':
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已订阅该产品"
                    )
                elif sub_data['status'] in ['past_due', 'unpaid']:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的未付款订阅，请先处理现有订阅"
                    )
                elif sub_data['status'] == 'canceled':
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已取消过该产品的订阅，如需重新订阅请联系客服"
                    )
                else:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的订阅记录"
                    )
        
        try:
            # 创建Stripe结账会话（订阅模式）
            checkout_session = stripe.checkout.Session.create(
                payment_method_types=["card"],
                line_items=[{
                    "price": product['stripe_price_id'],
                    "quantity": 1,
                }],
                mode="subscription",  # 订阅模式
                success_url=request.success_url,
                cancel_url=request.cancel_url,
                customer=customer['stripe_customer_id'],
                metadata={
                    **(request.metadata or {}),
                    "customer_id": request.customer_id,
                    "product_id": request.product_id,
                    "local_customer_id": request.customer_id,
                    "local_product_id": request.product_id
                }
            )
            
            logger.info(f"订阅支付会话创建成功: {checkout_session.id} 客户: {request.customer_id}")
            return {
                "checkout_url": checkout_session.url,
                "session_id": checkout_session.id,
                "customer_id": request.customer_id,
                "product_id": request.product_id
            }
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"创建订阅支付会话失败: {str(e)}")
            raise HTTPException(status_code=500, detail="创建订阅支付会话失败")
    
    def get_subscription(self, subscription_id: str) -> Optional[Dict[str, Any]]:
        """获取订阅信息"""
        # 重新加载最新数据，确保返回最新状态
        self.reload_data()
        return self.subscriptions.get(subscription_id)
    
    def list_subscriptions(self, limit: int = 100, offset: int = 0) -> List[Dict[str, Any]]:
        """列出所有订阅"""
        # 重新加载最新数据，确保返回最新状态
        self.reload_data()
        subscriptions_list = list(self.subscriptions.values())
        return subscriptions_list[offset:offset + limit]
    
    def get_customer_subscriptions(self, customer_id: str) -> List[Dict[str, Any]]:
        """获取客户的所有订阅"""
        # 重新加载最新数据，确保返回最新状态
        self.reload_data()
        customer_subs = []
        for sub_data in self.subscriptions.values():
            if sub_data['customer_id'] == customer_id:
                # 添加产品和客户信息
                if self.product_service:
                    product = self.product_service.get_product(sub_data['product_id'])
                    sub_data_with_details = sub_data.copy()
                    sub_data_with_details['product'] = product
                    if self.customer_service:
                        customer = self.customer_service.get_customer(sub_data['customer_id'])
                        sub_data_with_details['customer'] = customer
                    customer_subs.append(sub_data_with_details)
                else:
                    customer_subs.append(sub_data)
        return customer_subs
    
    def update_subscription(self, subscription_id: str, request: SubscriptionUpdateRequest) -> Optional[Dict[str, Any]]:
        """更新订阅信息"""
        if subscription_id not in self.subscriptions:
            return None
        
        subscription_data = self.subscriptions[subscription_id]
        
        try:
            # 更新Stripe订阅
            update_data = {}
            if request.metadata is not None:
                update_data['metadata'] = request.metadata
            
            if update_data:
                stripe.Subscription.modify(
                    subscription_data['stripe_subscription_id'],
                    **update_data
                )
            
            # 更新本地数据
            for key, value in update_data.items():
                subscription_data[key] = value
            
            subscription_data['updated_at'] = datetime.now().isoformat()
            self.subscriptions[subscription_id] = subscription_data
            DataStore.save_data(Config.SUBSCRIPTIONS_FILE, self.subscriptions)
            
            logger.info(f"订阅更新成功: {subscription_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"更新订阅失败: {str(e)}")
            raise HTTPException(status_code=500, detail="更新订阅失败")
    
    def cancel_subscription(self, subscription_id: str, cancel_at_period_end: bool = True) -> Optional[Dict[str, Any]]:
        """取消订阅"""
        if subscription_id not in self.subscriptions:
            return None
        
        subscription_data = self.subscriptions[subscription_id]
        
        try:
            if cancel_at_period_end:
                # 在周期结束时取消
                stripe.Subscription.modify(
                    subscription_data['stripe_subscription_id'],
                    cancel_at_period_end=True
                )
                # 不更新状态,使用webhook更新
                # subscription_data['cancel_at_period_end'] = True
            else:
                # 立即取消
                stripe.Subscription.delete(subscription_data['stripe_subscription_id'])
                # 不更新状态，使用webhook更新
                # subscription_data['status'] = 'canceled'

            subscription_data['updated_at'] = datetime.now().isoformat()
            self.subscriptions[subscription_id] = subscription_data
            DataStore.save_data(Config.SUBSCRIPTIONS_FILE, self.subscriptions)
            self.reload_data()
            logger.info(f"订阅取消成功: {subscription_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"取消订阅失败: {str(e)}")
            raise HTTPException(status_code=500, detail="取消订阅失败")

    def upgrade_subscription(self, subscription_id: str, request: SubscriptionUpgradeRequest) -> Optional[Dict[str, Any]]:
        """升级/降级订阅（切换产品）"""
        if subscription_id not in self.subscriptions:
            return None
        
        subscription_data = self.subscriptions[subscription_id]
        
        # 检查订阅状态，只允许对活跃订阅进行升级/降级
        if subscription_data['status'] != 'active':
            raise HTTPException(
                status_code=400, 
                detail=f"只能对活跃订阅进行升级/降级，当前订阅状态为: {subscription_data['status']}"
            )
        
        # 重新加载最新数据
        products_data = DataStore.load_data(Config.PRODUCTS_FILE)
        
        # 验证新产品是否存在
        new_product = products_data.get(request.new_product_id)
        if not new_product:
            raise HTTPException(status_code=404, detail="新产品不存在")
        
        # 检查是否切换到相同产品
        if subscription_data['product_id'] == request.new_product_id:
            raise HTTPException(status_code=400, detail="不能切换到相同产品")
        
        # 检查客户是否已有新产品的订阅
        for sub_id, sub_data in self.subscriptions.items():
            if (sub_id != subscription_id and 
                sub_data['customer_id'] == subscription_data['customer_id'] and 
                sub_data['product_id'] == request.new_product_id):
                if sub_data['status'] == 'active':
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已订阅该产品"
                    )
                elif sub_data['status'] in ['incomplete']:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的未付款订阅，请先处理现有订阅"
                    )
                else:
                    raise HTTPException(
                        status_code=400, 
                        detail="客户已有该产品的订阅记录"
                    )
        
        try:
            # 获取当前订阅的详细信息
            stripe_subscription = stripe.Subscription.retrieve(subscription_data['stripe_subscription_id'])
            
            # 获取当前订阅项目ID
            items = stripe_subscription.items()

            for key, value in items:
                if key == "items":
                    items = value
            # 修改当前subscription对应的产品
            current_subscription_item_id = items.data[0].id
            print(current_subscription_item_id)
            # 设置计费周期锚点
            billing_cycle_anchor = None
            if request.billing_cycle_anchor == "now":
                billing_cycle_anchor = "now"
            elif request.billing_cycle_anchor == "unchanged":
                billing_cycle_anchor = "unchanged"
            
            # 更新Stripe订阅
            updated_subscription = stripe.Subscription.modify(
                subscription_data['stripe_subscription_id'],
                items=[{
                    "id": current_subscription_item_id,
                    "price": new_product['stripe_price_id']
                }],
                proration_behavior=request.proration_behavior,
                billing_cycle_anchor=billing_cycle_anchor,
                expand=["latest_invoice.payment_intent"]
            )
            
            # 更新本地数据
            subscription_data['product_id'] = request.new_product_id
            subscription_data['status'] = updated_subscription.status
            subscription_data['current_period_start'] = updated_subscription.current_period_start
            subscription_data['current_period_end'] = updated_subscription.current_period_end
            subscription_data['updated_at'] = datetime.now().isoformat()
            
            # 更新元数据
            if request.metadata:
                subscription_data['metadata'] = {**(subscription_data.get('metadata', {})), **request.metadata}
            
            self.subscriptions[subscription_id] = subscription_data
            DataStore.save_data(Config.SUBSCRIPTIONS_FILE, self.subscriptions)
            
            logger.info(f"订阅升级/降级成功: {subscription_id} 从产品 {subscription_data['product_id']} 切换到 {request.new_product_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"升级/降级订阅失败: {str(e)}")
            import traceback
            logger.error(f"详细错误信息: {traceback.format_exc()}")
            raise HTTPException(status_code=500, detail=f"升级/降级订阅失败: {str(e)}")
    
    def renew_subscription(self, subscription_id: str) -> Optional[Dict[str, Any]]:
        """续订已取消的订阅"""
        if subscription_id not in self.subscriptions:
            return None
        
        subscription_data = self.subscriptions[subscription_id]
        
        # 检查订阅是否可以续订（必须是已取消且设置了到期后取消的订阅）
        if not subscription_data.get('cancel_at_period_end', False):
            raise HTTPException(
                status_code=400, 
                detail="只能续订已设置到期后取消的订阅"
            )
        
        if subscription_data['status'] not in ['active', 'past_due', 'unpaid']:
            raise HTTPException(
                status_code=400, 
                detail=f"只能续订活跃状态的订阅，当前状态为: {subscription_data['status']}"
            )
        
        try:
            # 取消到期后取消的设置
            stripe_subscription = stripe.Subscription.modify(
                subscription_data['stripe_subscription_id'],
                cancel_at_period_end=False
            )
            
            # 更新本地数据
            # TODO 最好使用webhook更新
            subscription_data['cancel_at_period_end'] = False
            subscription_data['status'] = stripe_subscription.status
            subscription_data['current_period_start'] = stripe_subscription.current_period_start
            subscription_data['current_period_end'] = stripe_subscription.current_period_end
            subscription_data['updated_at'] = datetime.now().isoformat()
            
            self.subscriptions[subscription_id] = subscription_data
            DataStore.save_data(Config.SUBSCRIPTIONS_FILE, self.subscriptions)
            self.reload_data()
            logger.info(f"订阅续订成功: {subscription_id}")
            return subscription_data
            
        except stripe.error.StripeError as e:
            logger.error(f"Stripe错误: {str(e)}")
            raise HTTPException(status_code=400, detail=f"Stripe错误: {str(e)}")
        except Exception as e:
            logger.error(f"续订订阅失败: {str(e)}")
            raise HTTPException(status_code=500, detail="续订订阅失败")

    def reload_data(self):
        """重新加载数据"""
        self.subscriptions = DataStore.load_data(Config.SUBSCRIPTIONS_FILE)
